﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Gmantis.Controls
{
    public abstract class InputEventArgs : EventArgs
    {
        internal InputEventArgs(System.Windows.RoutedEventArgs originalArgs)
        {
            this.OriginalEventArgs = originalArgs;
            this.PointerDeviceType = GetPointerType(originalArgs);
        }

        internal InputEventArgs(System.Windows.RoutedEventArgs originalArgs, PointerDeviceType pointerType)
        {
            this.OriginalEventArgs = originalArgs;
            this.PointerDeviceType = pointerType;
        }

        internal static bool GetIsHandled(System.Windows.RoutedEventArgs e)
        {
            if (e is MouseButtonEventArgs)
            {
                return ((MouseButtonEventArgs)e).Handled;
            }
            if (e is ManipulationStartedEventArgs)
            {
                return ((ManipulationStartedEventArgs)e).Handled;
            }
            if (e is ManipulationDeltaEventArgs)
            {
                return ((ManipulationDeltaEventArgs)e).Handled;
            }
            return ((e is ManipulationCompletedEventArgs) && ((ManipulationCompletedEventArgs)e).Handled);
        }

        public static PointerDeviceType GetPointerType(System.Windows.RoutedEventArgs originalArgs)
        {
            if (originalArgs is MouseEventArgs)
            {
                MouseEventArgs args = originalArgs as MouseEventArgs;
                switch (args.StylusDevice.DeviceType)
                {
                    case TabletDeviceType.Stylus:
                        return PointerDeviceType.Pen;

                    case TabletDeviceType.Touch:
                        return PointerDeviceType.Touch;
                }
            }
            return PointerDeviceType.Mouse;
        }

        public Point GetPosition(UIElement relativeTo)
        {
            return GetPosition(this.OriginalEventArgs, relativeTo);
        }

        public static Point GetPosition(System.Windows.RoutedEventArgs args, UIElement relativeTo)
        {
            if (args is MouseEventArgs)
            {
                return ((MouseEventArgs)args).GetPosition(relativeTo);
            }
            if (args is ManipulationDeltaEventArgs)
            {
                ManipulationDeltaEventArgs args2 = args as ManipulationDeltaEventArgs;
                return args2.ManipulationContainer.GmTransformToVisual(relativeTo).Transform(args2.ManipulationOrigin);
            }
            if (args is ManipulationStartedEventArgs)
            {
                ManipulationStartedEventArgs args3 = args as ManipulationStartedEventArgs;
                return args3.ManipulationContainer.GmTransformToVisual(relativeTo).Transform(args3.ManipulationOrigin);
            }
            return new Point();
        }

        internal static void SetIsHandled(System.Windows.RoutedEventArgs e, bool handled)
        {
            if (e is MouseButtonEventArgs)
            {
                ((MouseButtonEventArgs)e).Handled = handled;
            }
            else if (e is ManipulationStartedEventArgs)
            {
                ((ManipulationStartedEventArgs)e).Handled = handled;
            }
            else if (e is ManipulationDeltaEventArgs)
            {
                ((ManipulationDeltaEventArgs)e).Handled = handled;
            }
            else if (e is ManipulationCompletedEventArgs)
            {
                ((ManipulationCompletedEventArgs)e).Handled = handled;
            }
        }

        // Properties
        public bool Handled
        {
            get
            {
                return GetIsHandled(this.OriginalEventArgs);
            }
            set
            {
                SetIsHandled(this.OriginalEventArgs, value);
            }
        }

        public System.Windows.RoutedEventArgs OriginalEventArgs { get; private set; }

        public object OriginalSource
        {
            get
            {
                return this.OriginalEventArgs.OriginalSource;
            }
        }

        public PointerDeviceType PointerDeviceType { get; private set; }
    }

    public abstract class ZoomEventArgs : InputEventArgs
    {
        internal ZoomEventArgs(ZoomHelper zoomHelper, System.Windows.RoutedEventArgs originalArgs, PointerDeviceType pointerType)
            : base(originalArgs, pointerType)
        {
            this.ZoomHelper = zoomHelper;
        }

        internal ZoomHelper ZoomHelper { get; private set; }
    }

    public class ZoomStartedEventArgs : ZoomEventArgs
    {
        internal ZoomStartedEventArgs(ZoomHelper helper, System.Windows.RoutedEventArgs originalArgs, PointerDeviceType type)
            : base(helper, originalArgs, type)
        {
        }
    }

    public class ZoomDeltaEventArgs : ZoomEventArgs
    {
        // Methods
        internal ZoomDeltaEventArgs(ZoomHelper helper, System.Windows.RoutedEventArgs originalArgs, PointerDeviceType pointerType, Point deltaScale, Point cumulativeScale, Point deltaTranslation, Point cumulativeTranslation)
            : base(helper, originalArgs, pointerType)
        {
            this.DeltaScale = deltaScale;
            this.CumulativeScale = cumulativeScale;
            this.DeltaTranslation = deltaTranslation;
            this.CumulativeTranslation = cumulativeTranslation;
        }

        public void Complete()
        {
            base.ZoomHelper.Complete(null);
        }

        // Properties
        public Point CumulativeScale { get; private set; }

        public Point CumulativeTranslation { get; private set; }

        public Point DeltaScale { get; private set; }

        public Point DeltaTranslation { get; private set; }

        public double UniformCumulativeScale
        {
            get
            {
                return Math.Max(this.CumulativeScale.X, this.CumulativeScale.Y);
            }
        }

        public double UniformDeltaScale
        {
            get
            {
                return Math.Max(this.DeltaScale.X, this.DeltaScale.Y);
            }
        }
    }

    public class ZoomCompletedEventArgs : ZoomEventArgs
    {
        // Methods
        internal ZoomCompletedEventArgs(ZoomHelper helper, System.Windows.RoutedEventArgs originalArgs, PointerDeviceType pointerType, Point cumulativeScale, Point cumulativeTranslation)
            : base(helper, originalArgs, pointerType)
        {
            this.CumulativeScale = cumulativeScale;
            this.CumulativeTranslation = cumulativeTranslation;
        }

        // Properties
        public Point CumulativeScale { get; set; }

        public Point CumulativeTranslation { get; private set; }

        public double UniformCumulativeScale
        {
            get
            {
                return Math.Max(this.CumulativeScale.X, this.CumulativeScale.Y);
            }
        }
    }

    public abstract class ScrollEventArgs : InputEventArgs
    {
        // Methods
        internal ScrollEventArgs(ScrollHelper scrollHelper, System.Windows.RoutedEventArgs originalArgs, PointerDeviceType pointerType)
            : base(originalArgs, pointerType)
        {
            this.ScrollHelper = scrollHelper;
        }

        // Properties
        internal ScrollHelper ScrollHelper { get; private set; }

    }

    public class ScrollStartedEventArgs : ScrollEventArgs
    {
        // Methods
        internal ScrollStartedEventArgs(ScrollHelper helper, System.Windows.RoutedEventArgs originalArgs, PointerDeviceType pointerType)
            : base(helper, originalArgs, pointerType)
        {
        }
    }

    public class ScrollDeltaEventArgs : ScrollEventArgs
    {
        // Methods
        internal ScrollDeltaEventArgs(ScrollHelper helper, System.Windows.RoutedEventArgs originalArgs, PointerDeviceType pointerType, double deltaScroll, double cumulativeScroll)
            : base(helper, originalArgs, pointerType)
        {
            this.DeltaScroll = deltaScroll;
            this.CumulativeScroll = cumulativeScroll;
        }

        public void Complete()
        {
            base.ScrollHelper.Complete(null);
        }

        // Properties
        public double CumulativeScroll { get; private set; }

        public double DeltaScroll { get; private set; }
    }

    public class ScrollCompletedEventArgs : ScrollEventArgs
    {
        // Methods
        internal ScrollCompletedEventArgs(ScrollHelper helper, System.Windows.RoutedEventArgs originalArgs, PointerDeviceType pointerType, double cumulativeScroll)
            : base(helper, originalArgs, pointerType)
        {
            this.CumulativeScroll = cumulativeScroll;
        }

        // Properties
        public double CumulativeScroll { get; private set; }
    }

    public abstract class DragEventArgs : InputEventArgs
    {
        internal DragEventArgs(DragHelper dragHelper, System.Windows.RoutedEventArgs originalArgs, PointerDeviceType pointerType)
            : base(originalArgs, pointerType)
        {
            this.DragHelper = dragHelper;
        }

        public DragHelper DragHelper { get; private set; }
    }

    public class DragStartingEventArgs : DragEventArgs
    {
        // Methods
        internal DragStartingEventArgs(DragHelper helper, System.Windows.RoutedEventArgs originalArgs, PointerDeviceType pointerType, DragHelperMode mode, bool captureElementOnPointerPressed, double initialThreshold)
            : base(helper, originalArgs, pointerType)
        {
            this.Mode = mode;
            this.CaptureElementOnPointerPressed = captureElementOnPointerPressed;
            this.InitialThreshold = initialThreshold;
        }

        // Properties
        public bool Cancel { get; set; }

        public bool CaptureElementOnPointerPressed { get; set; }

        public double InitialThreshold { get; set; }

        public DragHelperMode Mode { get; set; }
    }

    public class DragStartedEventArgs : DragEventArgs
    {
        internal DragStartedEventArgs(DragHelper helper, System.Windows.RoutedEventArgs originalArgs, PointerDeviceType pointerType, Point origin,
            DragDirection direction)
            : base(helper, originalArgs, pointerType)
        {
            this.Origin = origin;
            this.Direction = direction;
        }

        internal DragDirection Direction { get; private set; }
        public Point Origin { get; private set; }
    }

    public class DragDeltaEventArgs : DragEventArgs
    {
        // Methods
        internal DragDeltaEventArgs(DragHelper helper, System.Windows.RoutedEventArgs originalArgs, PointerDeviceType pointerType, Point deltaTranslation, Point cumulativeTranslation, bool isInertial)
            : base(helper, originalArgs, pointerType)
        {
            this.DeltaTranslation = deltaTranslation;
            this.CumulativeTranslation = cumulativeTranslation;
            this.IsInertial = isInertial;
        }

        public void Complete()
        {
            base.DragHelper.Complete(null);
        }

        // Properties
        public Point CumulativeTranslation { get; private set; }

        public Point DeltaTranslation { get; private set; }

        public bool IsInertial { get; private set; }
    }

    public class DragCompletedEventArgs : DragEventArgs
    {
        // Methods
        internal DragCompletedEventArgs(DragHelper helper, System.Windows.RoutedEventArgs originalArgs, PointerDeviceType pointerType, Point cumulativeTranslation)
            : base(helper, originalArgs, pointerType)
        {
            this.CumulativeTranslation = cumulativeTranslation;
        }

        // Properties
        public Point CumulativeTranslation { get; internal set; }
    }

    public class DragInertiaStartedEventArgs : DragEventArgs
    {
        // Methods
        internal DragInertiaStartedEventArgs(DragHelper helper, System.Windows.RoutedEventArgs originalArgs, PointerDeviceType pointerType, Point finalVelocity, double desiredDeceleration)
            : base(helper, originalArgs, pointerType)
        {
            this.Velocity = finalVelocity;
            this.DesiredDeceleration = desiredDeceleration;
        }

        // Properties
        public double DesiredDeceleration { get; set; }
        public Point Velocity { get; private set; }
    }

    public class ValidateInputEventArgs : EventArgs
    {
        // Properties
        public string Input { get; internal set; }

        public bool IsValidInput { get; set; }
    }

    public class TappedEventArgs : InputEventArgs
    {
        public TappedEventArgs(RoutedEventArgs originalArgs)
            : base(originalArgs)
        {
        }
    }

    public enum PointerDeviceType
    {
        Mouse,
        Touch,
        Pen
    }
}
